﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ERPStore.Extensions;

using CloudSoft.Extensions;
using System.IO;

namespace ERPStore.MockConnector
{
	public class DocumentService : ERPStore.Services.IDocumentService
	{
		public DocumentService(ERPStore.Logging.ILogger logger)
		{
			this.Logger = logger;
		}

		protected ERPStore.Logging.ILogger Logger { get; private set; }

		#region IDocumentService Members

		public ERPStore.Models.Media GetByCode(string externalDocumentId)
		{
			var catalogService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ICatalogService>();
			var product = catalogService.GetProductByCode(externalDocumentId);

			return product.DefaultImage;
		}

		public byte[] DownloadImageAndSave(string uri, string fileName, out string contentType)
		{
			throw new NotImplementedException();
		}

		public void WriteImage(string url, System.IO.Stream outputStream, out string contentType)
		{
			throw new NotImplementedException();
		}

		public string GetFileNameFromUrl(string url)
		{
			throw new NotImplementedException();
		}

		public void SaveMedia(ERPStore.Models.Media media)
		{
			throw new NotImplementedException();
		}

		public byte[] ResizeImageTo(byte[] content, int width)
		{
			throw new NotImplementedException();
		}

		public IList<ERPStore.Models.Media> GetMediaList(ERPStore.Models.Product product)
		{
			throw new NotImplementedException();
		}

		public IList<ERPStore.Models.Media> GetMediaList(ERPStore.Models.ProductCategory product)
		{
			throw new NotImplementedException();
		}

		public IList<ERPStore.Models.Media> GetMediaList(ERPStore.Models.Brand product)
		{
			throw new NotImplementedException();
		}

		public IList<ERPStore.Models.Media> GetMediaList(ERPStore.Models.Order product)
		{
			throw new NotImplementedException();
		}

		public byte[] GetDocumentContentByCode(string externalDocumentId)
		{
			throw new NotImplementedException();
		}

		public byte[] GetDocumentContentByKey(string key)
		{
			throw new NotImplementedException();
		}

		bool ERPStore.Services.IDocumentService.WriteImage(string url, System.IO.Stream outputStream, out string contentType)
		{
			throw new NotImplementedException();
		}


		public IList<ERPStore.Models.ModelInfo> GetModelListByExternalDocumentId(string externalDocumentId)
		{
			throw new NotImplementedException();
		}

		#endregion

		Models.Media Services.IDocumentService.GetByCode(string externalDocumentId)
		{
			throw new NotImplementedException();
		}

		byte[] Services.IDocumentService.DownloadImageAndSave(string uri, string fileName, out string contentType)
		{
			throw new NotImplementedException();
		}

		string Services.IDocumentService.GetFileNameFromUrl(string url)
		{
			throw new NotImplementedException();
		}

		void Services.IDocumentService.SaveMedia(Models.Media media)
		{
			throw new NotImplementedException();
		}

		byte[] Services.IDocumentService.ResizeImageTo(byte[] content, int width)
		{
			throw new NotImplementedException();
		}

		byte[] Services.IDocumentService.GetDocumentContentByCode(string externalDocumentId)
		{
			throw new NotImplementedException();
		}

		IList<Models.Media> Services.IDocumentService.GetMediaList(Models.Product product)
		{
			throw new NotImplementedException();
		}

		IList<Models.Media> Services.IDocumentService.GetMediaList(Models.ProductCategory productCategory)
		{
			throw new NotImplementedException();
		}

		IList<Models.Media> Services.IDocumentService.GetMediaList(Models.Brand brand)
		{
			throw new NotImplementedException();
		}

		IList<Models.Media> Services.IDocumentService.GetMediaList(Models.Order order)
		{
			throw new NotImplementedException();
		}

		byte[] Services.IDocumentService.GetDocumentContentByKey(string key)
		{
			throw new NotImplementedException();
		}

		IList<Models.ModelInfo> Services.IDocumentService.GetModelListByExternalDocumentId(string externalDocumentId)
		{
			throw new NotImplementedException();
		}

		public string GetFileName(string externalDocumentId, int width, int height, string fileName, out string mimeType, out string reason)
		{
			var rootImagePath = global::ERPStore.GlobalConfiguration.Configuration.Settings.ImagePath.TrimEnd('\\').TrimEnd('/');

			var fullFileName = string.Format(@"{0}\{1}x{2}\{3}", rootImagePath, width, height, externalDocumentId);
			var fileInfo = new System.IO.FileInfo(fullFileName);
			mimeType = "image/png";
			reason = null;

			if (!fileInfo.Exists)
			{
				// Chemin vers le fichier
				var media = GetByCode(externalDocumentId);
				if (media == null)
				{
					reason = "ExternalDocumentId does not exists";
					return null;
				}

				CreateFile(media, width, height, externalDocumentId, fileName);
			}

			return fullFileName;
		}

		private void CreateFile(global::ERPStore.Models.Media media, int width, int height, string externalDocumentId, string fileName)
		{
			var rootImagePath = global::ERPStore.GlobalConfiguration.Configuration.Settings.ImagePath.TrimEnd('\\').TrimEnd('/');
			var fullFileName = string.Format(@"{0}\0x0\{1}", rootImagePath, externalDocumentId);
			byte[] content = null;
			var errorOnDownload = false;
			var fi = new System.IO.FileInfo(fullFileName);
			var failReason = string.Empty;

			// 1 - On regarde si le fichier n'existe pas au format maxi
			if (fi.Exists
				&& fi.Length > 0)
			{
				try
				{
					var image = System.Drawing.Image.FromFile(fullFileName);
					using (var ms = new MemoryStream())
					{
						image.Save(ms, image.RawFormat);
						content = ms.GetBuffer();
						ms.Close();
					}
				}
				catch (Exception ex)
				{
					failReason = ex.Message;
				}
			}

			// 2 - Traitment d'url externe
			// On charge le fichier que l'on ecrit localement
			if (content == null
				&& !media.ExternalUrl.IsNullOrTrimmedEmpty())
			{
				var webClient = new System.Net.WebClient();
				webClient.Headers.Add("user-agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)");
				webClient.Headers.Add("referer", media.ExternalUrl);

				var retryCount = 0;
				while (true)
				{
					try
					{
						content = webClient.DownloadData(media.ExternalUrl);

						if (content != null
							&& content.Length > 0)
						{
							// Sauvegarde de l'image au grand format
							using (var fs = new System.IO.FileStream(fullFileName, System.IO.FileMode.Create))
							{
								Logger.Debug("Create picture : {0}", fullFileName);
								fs.Write(content, 0, content.Length);
								fs.Flush();
								fs.Close();
							}

							var verif = System.Drawing.Image.FromFile(fullFileName);
							if (verif.Height < 20
								|| verif.Width < 20)
							{
								var biex = new BadImageFormatException(string.Format("image is too small {0}x{1} from url {2}", verif.Height, verif.Width, media.ExternalUrl));
								biex.Data.Add("ExternalDocumentId", externalDocumentId);
								throw biex;
							}
						}
						else
						{
							errorOnDownload = true;
						}
						break;
					}
					catch (System.Net.WebException webEx)
					{
						failReason = webEx.Message + "\r\n" + webEx.Status;
						errorOnDownload = true;
						break;
					}
					catch (Exception ex)
					{
						if (retryCount > 3)
						{
							failReason = string.Format("Too many retry for download image {0}", externalDocumentId);
							break;
						}
						errorOnDownload = true;
						retryCount++;
						System.Threading.Thread.Sleep(500);
					}
				}
			}

			if (content == null
				&& !errorOnDownload)
			{
				Logger.Debug("Process db blob : {0}", externalDocumentId);
				// Chargement du contenu dans la base de donnée
				try
				{
					content = GetDocumentContentByCode(externalDocumentId);
				}
				catch (Exception ex)
				{
					content = null;
					failReason = ex.Message;
				}
			}

			if (content == null
				|| content.Length < 140)
			{
				var ex = new Exception("Image not found");
				ex.Data.Add("ExternalDocumentId", externalDocumentId);
				ex.Data.Add("MediaId", media.Id);
				ex.Data.Add("ExternalUrl", media.ExternalUrl);
				ex.Data.Add("FailReason", failReason);
				throw ex;
			}

			var settings = new ImageResizer.ResizeSettings()
			{
				MaxWidth = Math.Min(400, width),
				MaxHeight = Math.Min(400, height),
				Format = "png",
				Mode = ImageResizer.FitMode.Pad,
			};

			if (width == 0)
			{
				settings.MaxWidth = 400;
			}
			if (height == 0)
			{
				settings.MaxHeight = 400;
			}

			var img = ImageResizer.ImageBuilder.Current.Build(content, settings);

			var sizedImageFile = string.Format(@"{0}\{1}x{2}\{3}", rootImagePath, width, height, externalDocumentId);
			CreateDeepDirectory(System.IO.Path.GetDirectoryName(sizedImageFile));

			// Creation du fichier
			using (var fs = new System.IO.FileStream(sizedImageFile, System.IO.FileMode.Create))
			{
				img.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
				Logger.Debug("Create picture : {0}", sizedImageFile);
			}
		}

		private void CreateDeepDirectory(string path)
		{
			if (System.IO.Directory.Exists(path))
			{
				return;
			}

			var parts = path.Split('\\').ToList();
			var paths = new List<string>();
			while (parts.Count() != 1)
			{
				var part = parts.Last();
				paths.Insert(0, path);
				path = path.Replace(part, "");
				parts.RemoveAt(parts.Count - 1);
			}

			foreach (var item in paths)
			{
				if (!System.IO.Directory.Exists(item))
				{
					System.IO.Directory.CreateDirectory(item);
				}
			}
		}

	}
}
